﻿using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using UpdateApp.Config;

namespace UpdateApp.Download
{
    /// <summary>
    /// 文件下载
    /// </summary>
    internal class DownloadWrapper : IDisposable
    {
        private readonly IDownloadCallback _callback;
        private readonly HttpClient _httpClient;

        /// <summary>
        /// ctor
        /// </summary>
        public DownloadWrapper(
            IDownloadCallback callback)
        {
            _callback = callback;
            var handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback = (request, certificate, chain, error) => true;
            _httpClient = new HttpClient(handler);
        }

        /// <summary>
        /// http get下载文件
        /// </summary>
        /// <param name="url">文件地址</param>
        /// <returns></returns>
        public async Task GetAsync(string? url, CancellationToken cancellationToken)
        {
            using (var rep = await _httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
            {
                try
                {
                    var length = rep.Content.Headers.ContentLength;
                    var data = new byte[1024 * 1024];
                    var readLength = 0;
                    var filename = string.IsNullOrWhiteSpace(rep.Content.Headers.ContentDisposition?.FileNameStar) ? rep.Content.Headers.ContentDisposition?.FileName : rep.Content.Headers.ContentDisposition.FileNameStar;
                    using (var stream = await rep.Content.ReadAsStreamAsync(cancellationToken))
                    {
                        try
                        {
                            var totalReadLength = 0L;
                            while ((readLength = await stream.ReadAsync(data, 0, data.Length)) > 0)
                            {
                                var processData = ToData(length);
                                processData.IsFirstPacket = totalReadLength == 0;
                                processData.FileName = filename;
                                processData.Data = new byte[readLength];
                                Buffer.BlockCopy(data, 0, processData.Data, 0, readLength);
                                totalReadLength += readLength;
                                if (length > 0)
                                    processData.Progress = Math.Round((totalReadLength * 1.0M / length.Value) * 100, 2);
                                else
                                    processData.Progress = 50;

                                _callback?.ReceiveDownloadDataAsync(processData);
                            }

                            var completeData = ToData(length);
                            completeData.FileName = filename;
                            completeData.DownloadType = DownloadType.Complete;
                            completeData.Progress = 100;
                            _callback?.ReceiveDownloadDataAsync(completeData);
                        }
                        catch (Exception e1)
                        {
                            e1.ShowError((Window)_callback);
                        }
                    }
                }
                catch (Exception e2)
                {
                    e2.ShowError((Window)_callback);
                }
            }
        }

        public void Dispose()
        {
            _httpClient?.Dispose();
        }

        #region private method
        /// <summary>
        /// DownloadDataDto
        /// </summary>
        private DownloadDataDto ToData(long? total)
        {
            return new DownloadDataDto { Total = total ?? -1 };
        }
        #endregion
    }
}
